/*
  Copyright (c) 2014 Dimitrij Gester

  "Smart RC TX" is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  "Smart RC TX" is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with "Smart RC TX"; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA
*/

package com.codeplex.smartrctx.configurator.main.model.control_commands;

import java.util.ArrayList;
import java.util.List;

public abstract class BaseSerializer extends Serializer {
	//
	// Compute a Dallas Semiconductor 8 bit CRC directly.
	// this is much slower, but much smaller, than the lookup table.
	//
	protected int crc8_update(int crc, int data){
		int inbyte = data;
		for (int i = 8; i > 0; i--) {
			byte  mix = (byte) ((crc ^ inbyte) & 0x01);
			crc >>= 1;
			if (mix != 0) crc ^= 0x8C;
			inbyte >>= 1;
		}
		return crc;
	}
	
	protected void addCRC(List<Byte> cmd) {
		int crc = 0;

		for(Byte b : cmd) {
			crc = crc8_update(crc,  b);
		}
		
		int crcHi = 0xE0 | (crc >> 4) & 0x0f;
		int crcLo = 0xD0 | (crc & 0x0f);
		cmd.add(0, (byte) crcLo);
		cmd.add(0, (byte) crcHi);
	}
	
	protected List<Byte> createCommandSequence(byte function, byte channel, int value) {		
		List<Byte> seq = new ArrayList<Byte>();

		encodeValue(value, seq, true);
		encodeCommitCommand(function, channel, seq);
		
		return seq;
	}

	protected List<Byte> encodeChannel(byte function, byte channel, int value) {
		return createCommandSequence(function, channel, value);
	}

	protected void serializeChannels(byte function, Integer[] channels) {
		for(byte channel = 0; channel < channels.length; channel++) {
			if(channels[channel] != null) {
				List<Byte> cmd = encodeChannel(function, channel, channels[channel]);
				
				addCRC(cmd);
				
				getCommandList().add(cmd);
			}
		}
	}

	protected void encodeCommitCommand(byte function, byte channel, List<Byte> seq) {
		seq.add((byte) (0x00 | (function & 0x07) << 3 | (channel & 0x07)));
	}

	protected void encodeValue(int value, List<Byte> seq, boolean primaryValue) {
		int txValue = value + 512;
		seq.add((byte) (0x80 | (txValue) & 0x3f));
		seq.add((byte) (0x40 | (primaryValue ? 0x10 : 0x00) | (txValue >> 6) & 0x0f));
	}
}
